#pragma once

#include <string>

#if defined(WIN32) || defined(_WIN32)
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif

namespace network {

    class Address {

    public:

        /**
          * @brief  默认构造一个ip为127.0.0.1，端口号为8080的地址
          */
        Address() : Address("127.0.0.1", 8080) {}

        /**
          * @brief  根据指定的ip和端口构造一个网络地址
          * @param  ip   网路地址对象的ip
          * @param  port 网络地址对象的端口
          */
        Address(const char *ip, unsigned short port);

        Address(const std::string &ip, unsigned short port) : Address(ip.c_str(), port) {}

        /**
          * @brief  根据指定的sockaddr_in构造一个网络地址
          * @param  address 指定的sockaddr_in
          */
        explicit Address(const struct sockaddr_in &address) : address_(address) {}

        /**
          * @brief  设置地址的ip
          * @param  ip ip
          */
        void setIp(const char *ip);

        void setIp(const std::string &ip) { setIp(ip.c_str()); }

        /**
          * @brief  设置地址的端口号
          * @param  port 端口号
          */
        void setPort(unsigned short port);

        /**
          * @brief  获取该网络地址的端口
          * @retval 端口
          */
        unsigned short getPort() const;

        /**
          * @brief  获取网络地址的ip
          * @retval ip
          */
        std::string getIp() const;

        /**
          * @brief  获取网络地址的sockaddr指针
          * @retval sockaddr指针
          */
        struct sockaddr *getSockAddr() { return (struct sockaddr *) &address_; }

        /**
          * @brief  获取网络地址的sockaddr_in指针
          * @retval sockaddr_in指针
          */
        struct sockaddr_in *getSockAddrIn() { return &address_; }

    private:

        // 地址结构体
        struct sockaddr_in address_{0};

    };

    Address::Address(const char *ip, unsigned short port) {
        address_.sin_family = AF_INET;
        address_.sin_addr.s_addr = inet_addr(ip);
        address_.sin_port = htons(port);
    }

    void Address::setIp(const char *ip) {
        address_.sin_addr.s_addr = inet_addr(ip);
    }

    void Address::setPort(unsigned short port) {
        address_.sin_port = htons(port);
    }

    unsigned short Address::getPort() const {
        return ntohs(address_.sin_port);
    }

    std::string Address::getIp() const {
        return {inet_ntoa(address_.sin_addr)};
    }

}